package gui.processor;

import gui.utils.HeatMapData;
import core.process.Codon;
import core.utils.Utils;
import core.process.Nucs;
import core.process.Align;
import core.process.Match;
import core.process.Indel;
import core.process.pack.IndelData;
import core.process.Post;
import core.rb.r.IR;
import core.rb.r.PR;
import core.rb.r.Pol;
import core.rb.IB;
import core.rb.PB;
import core.rb.MB;
import core.sb.SB;
import core.sb.s.Seq;
import core.utils.EPara;
import gui.Segl0;
import gui.North;
import gui.Segl2;
import gui.cen.Center;
import gui.utils.Para;
import java.io.File;
import java.lang.Math.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import rpgsdb.db.NK;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import javax.swing.JPanel;
import core.tree.nj.NJ;
import core.utils.BayesianData;
import gui.Segl1;
import gui.utils.ProgBar;
import java.io.BufferedReader;
import java.io.FileReader;
import javax.swing.JOptionPane;

/*Author: John Archer, Contact: john.archer.jpa@gmail.com*/
public class Processor {
    private Object call;
    public Processor(Object caller){this.call = caller;}
    private int task = -1;
    public void setTask(int t){task = t;}

    private static boolean B_LOCK = false;
    public void runTask(){
        if(task==Para.TASK_TREEDAR){try{tdar();}catch(Exception e){tdar=false;}}
        else if(task==Para.TASK_COUNT_STOP_CODONS){try{countStopCodons();}catch(Exception e){stops=false;}}
        else if(task==Para.TASK_RM_DATA){try{rmData();}catch(Exception e){}}
        else if(task==Para.TASK_ADD_PROJ){try{addProj();}catch(Exception e){}}
        else if(task==Para.TASK_RM_PROJ){try{rmProj();}catch(Exception e){}}
        else {
            if(B_LOCK==false){
                B_LOCK = true;
                try{
                    if(task==Para.TASK_TREE){tree();}
                    else if(task==Para.TASK_FILTER){filter();}
                    else if(task==Para.TASK_ADD_DATA){try{addData(((Segl1)call), Para.D_TITLE, Para.D_PATH);System.gc();}catch(Exception e){}}
                    else if(task==Para.TASK_DISPLAY){display();}
                    else if(task==Para.TASK_TSAVE){tSave();}
                    else if(task==Para.TASK_RSAVE){rSave();}
                    else if(task==Para.TASK_GENOTYPE){genotype();}
                    else if(task==Para.TASK_EXT_TREE){extTree();}
                    else if(task==Para.TASK_SAVE_INDELS){saveAdditional();}
                    else if(task==Para.TASK_VEME){vemeTable();}
                    else if(task==Para.TASK_BATCH){addBatchs();}
                    else if(task==Para.TASK_BARCODES){barcode();}
                }
                catch(Exception e){
                    B_LOCK = false;
                    idPrg(ProgBar.END);
                    dPrg(ProgBar.END, 0);
                }
                B_LOCK = false;
            }
            else{msg("Another task in progress.");}
        }
    }
    
    private void heatMap() throws Exception{
        msg("Heatmap Data");
        double maxEnt = -1;int maxCov = -1;
        SB ref = Segl0.db.getRef(Para.PID);
        double [] ent = new double[ref.get(0).getDNA().length()];
        int [] cov = new int[ref.get(0).getDNA().length()];
        char [] con =  new char[ref.get(0).getDNA().length()];
        char [] refSeq = Para.PB.getRef().getDNA().toCharArray();
        dPrg(ProgBar.START, Para.NUCS[0].length);
        for(int s=0; s<Para.NUCS[0].length; s++){
            int [] nucFreqs = {Para.NUCS[0][s],Para.NUCS[1][s],Para.NUCS[2][s],Para.NUCS[3][s]};
            cov[s] = Utils.sum(nucFreqs);
            ent[s] = Utils.getEnt(Para.NUCS[0][s],Para.NUCS[1][s],Para.NUCS[2][s],Para.NUCS[3][s], 0, cov[s]);
            con[s] = refSeq[s];
            if(cov[s] > maxCov){maxCov = cov[s];}
            if(ent[s] > maxEnt){maxEnt = ent[s];}
            dPrg(ProgBar.UPDATE, s);
        }
        dPrg(ProgBar.END, 0);
        double [] pCov = new double[ref.get(0).getDNA().length()];
        double [] pEnt = new double[ref.get(0).getDNA().length()];
        for(int s=0; s<pCov.length; s++){
            pCov[s] = ((double)cov[s] / (double)maxCov) * 100;
            pEnt[s] = ((double)ent[s] / (double)maxEnt) * 100;
        }
        Para.HEATMAP_DATA = new HeatMapData(pCov, con, pEnt);
    }

    private void saveAdditional() throws Exception{
        SB ref = Segl0.db.getRef(Para.PID);
        int [] cov = new int[ref.get(0).getDNA().length()];
        double [] ent = new double[ref.get(0).getDNA().length()];
        double [] nonCon = new double[Para.PB.getRef().getDNA().length()];
        IndelData tINDELdata = getIndels(Para.PB, this);
        int[][] ins = tINDELdata.getIns();
        int[][] del = tINDELdata.getDels();
        int [] T_HPS_CATS = Utils.getHPSLens(Para.PB.getRef().getDNA());
        PrintWriter of = new PrintWriter(new FileWriter(Utils.getFile(new JPanel(), false).getSelectedFile()), false);
        of.print("Site\tcover\tnon_consensus\tentropy\thps");
        for(int c=1; c<EPara.MAXINDEL; c++){of.print("\tins_len_" +c);}
        for(int c=1; c<EPara.MAXINDEL; c++){of.print("\tdel_len_" +c);}
        of.print("\n");
        dPrg(ProgBar.START, Para.NUCS[0].length);
        for(int s=0; s<Para.NUCS[0].length; s++){
            int [] nucFreqs = {Para.NUCS[0][s],Para.NUCS[1][s],Para.NUCS[2][s],Para.NUCS[3][s]};
            cov[s] = Utils.sum(nucFreqs);
            ent[s] = Utils.getEnt(Para.NUCS[0][s],Para.NUCS[1][s],Para.NUCS[2][s],Para.NUCS[3][s], 0, cov[s]);
            if(cov[s]==0){nonCon[s] = 0;}
            else{nonCon[s] = (double)Utils.sumOmitMax(nucFreqs);}

            String codons = "";
            if((s - Para.FRAME)%3==0 && s<(Para.CON.length - 3)){
                HashMap <String, Integer> siteCodons = Para.CODONS[s];
                Iterator iter = siteCodons.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry pairs = (Map.Entry)iter.next();
                    String key = (String)pairs.getKey();
                    int value = ((Integer)pairs.getValue()).intValue();
                    codons = codons + key+":"+Utils.trans(key)+" ("+value+"), ";
                }
                codons = codons +" ["+ (codons.split(",").length - 1) +"]";
            }else{codons="";}
            boolean saveRow = false;
            double [] vals = {(double)Para.NUCS[0][s]/(double)cov[s], (double)Para.NUCS[1][s]/(double)cov[s], (double)Para.NUCS[2][s]/(double)cov[s], (double)Para.NUCS[3][s]/(double)cov[s]};
            if(Utils.getSecondHighestValue(vals)>=((double)EPara.MIN_FREQ_HIGHLIGHT/100.00) && T_HPS_CATS[s]<=EPara.HPS_LENGTH){saveRow = true;}
            else{saveRow = false;}
            if(saveRow){
                of.print(s + "\t" + cov[s] + "\t" + nonCon[s] + "\t" + ent[s] + "\t" + T_HPS_CATS[s]);
                for(int c=1; c<EPara.MAXINDEL; c++){of.print("\t" +ins[c][s]);}
                for(int c=1; c<EPara.MAXINDEL; c++){of.print("\t" +del[c][s]);}
                of.print("\n");
            }
            dPrg(ProgBar.UPDATE, s);
        }
        dPrg(ProgBar.END, 0);
        of.close();
    }

    private static boolean stops = false;
    private void countStopCodons() throws Exception{
        if(stops==false){
            stops = true;
            Para.STOPS = 0;
            for(int x=0; x<Para.CODONS.length-3; x++){
                if((x - Para.FRAME)%3==0){
                    HashMap <String, Integer> sCods = Para.CODONS[x];
                    try{
                        Iterator iter = sCods.entrySet().iterator();
                        Map.Entry pairs = (Map.Entry)iter.next();
                        if(Utils.trans((String)pairs.getKey()).equals("*")){Para.STOPS++;}
                    }
                    catch(Exception e){/*empty hash so not interesting*/}
                }
            }
            if(call.getClass() == Center.class){((Center)call).updateTable();}
            stops = false;
        }
    }

    private static boolean tdar = false;
    private void tdar() throws Exception{
        if(tdar==false){
            tdar = true;
            SB sb = new SB();
            String dna;int start ,end;
            double thesh = EPara.POSTFILT/100.00;
            for(int x=0; x<Para.RTD.size(); x++){
                if(Para.RTD.get(x).getStart()<=Para.TPOS && Para.RTD.get(x).getEnd()>Para.TPOS + Para.TREEDAR_WIN){
                    int len = Para.RTD.get(x).getEnd() - Para.RTD.get(x).getStart();
                    char [] rchars = new char[len];
                    for(int s=0; s<len; s++){rchars[s] = '*';}
                    ArrayList <Pol> polys = Para.RTD.get(x).getPols();
                    for (int p = 0; p < polys.size(); p++) {
                        if (!polys.get(p).isIns()){
                            if(polys.get(p).isDel()){rchars[polys.get(p).getTLoc() - Para.RTD.get(x).getStart()] = '-';}
                            else{
                                if(polys.get(p).isDel()){rchars[polys.get(p).getTLoc() - Para.RTD.get(x).getStart()] = '-';}
                                else{
                                    if(Para.POSTS!=null){
                                        if(polys.get(p).getPost() >= thesh){rchars[polys.get(p).getTLoc() - Para.RTD.get(x).getStart()] = polys.get(p).getChar();}
                                    }
                                    else{rchars[polys.get(p).getTLoc() - Para.RTD.get(x).getStart()] = polys.get(p).getChar();}
                                }
                            }
                        }
                    }
                    start = Para.TPOS - Para.RTD.get(x).getStart();
                    end = start + Para.TREEDAR_WIN;
                    dna = "";
                    for (int s = start; s < end; s++){dna += rchars[s];}
                    sb.add(new Seq(Para.RTD.get(x).I(),dna,false));
                }
            }
            sb.rmDups();
            sb.rmSeqsWithNoInfo();
            if(sb.getSize()>=5){Para.TDAR = new NJ(null).build(sb, true);}
            else{Para.TDAR = null;}
            tdar = false;
        }
    }

    private void filter() throws Exception{
        if(Para.POSTS==null ||
                Para.PREDHPSMINM != Para.PREDHPSMINMHIST ||
                Para.PREDHPSPLUSM != Para.PREDHPSPLUSMHIST ||
                Para.PREDHPSLEN != Para.PREDHPSLENHIST
                ){
            BayesianData expt = getExpt();
            Para.POSTS = getPosts(
                        expt.getNFreqs(),
                        expt.getCover(), ((double)Para.PREDHPSMINM/10000.00),
                        ((double)Para.PREDHPSPLUSM/10000.00),
                        Para.HPS_CATS,Para.PREDHPSLEN
                    );
            Para.POSTPROJID = Para.PID;
            new Post(Para.PB, Para.POSTS).setPosts();
            Para.PREDHPSMINMHIST = Para.PREDHPSMINM;
            Para.PREDHPSPLUSMHIST = Para.PREDHPSPLUSM;
            Para.PREDHPSLENHIST = Para.PREDHPSLEN;
        }
        msg("Nucleotide Frequencies");
        Para.NUCS = Processor.getNucs(Para.PB, this, (double)EPara.POSTFILT/100.00);
        Para.CON = Utils.getCon(Para.NUCS, EPara.MIN_COV_CON);
        msg("Codon Frequencies");
        Para.CODONS = getCodons(Para.PB, this, (double)EPara.POSTFILT/100.00);
        heatMap();
        try{if(call.getClass() == Center.class){
            ((Center)call).updateTable();
            ((Center)call).updateReads();
            ((Center)call).updateTree();
            ((Center)call).setFilterLVL_label();
            ((Center)call).updatePlots();
        }}catch(Exception e){}
        msg("");
    }

    //get 'A', 'T', 'G', 'C', '-' priors
    private BayesianData getExpt() throws Exception{
        int [][] nfreqs = null;
        ArrayList <NK> data = Segl0.db.getDataNK(Para.PID);
        for(int x=0; x<data.size(); x++){
            msg("Priors ("+(x+1)+" of "+(data.size())+" )");
            PB pb = PB.load(getPBPath(Para.PID, data.get(x).getK()));
            if(x==0){nfreqs = Processor.getNucs(pb, this, -1);}
            else{Utils.add(Processor.getNucs(pb, this, -1), nfreqs);}
        }
        double [][] nf = Utils.addVal(0.0000000001 * data.size(), nfreqs);
        return new BayesianData(nf, Utils.sumCols(nf));
    }

    private double [][] getPosts(double [][] exptFreqs, double [] exptCov, double hps_minus, double hps_plus, int [] hpsCat, int hpsLen){
        msg("Calculating Posteriors");
        double [][] posts = new double[exptFreqs.length][exptFreqs[0].length];
        this.dPrg(ProgBar.START, exptFreqs[0].length);
        for(int s=0; s<exptFreqs[0].length; s++){
            for(int b=0; b<exptFreqs.length; b++){
                posts[b][s] = getPost(
                        (exptFreqs[b][s]),
                        (hpsCat[s] <= hpsLen) ? hps_minus : hps_plus,
                        (exptCov[s] - exptFreqs[b][s])
                );
            }
            this.dPrg(ProgBar.UPDATE, s);
        }
        this.dPrg(ProgBar.END, 0);
        return posts;
    }

    private double getPost(double exptObs, double e, double exptAbs){
        double num = (1 - e) * exptObs;
        double denom = num + ((1 - (1 - e)) * exptAbs);
        return (num / denom);
    }

    public void msg(String msg){
        if(call.getClass() == Segl1.class){((Segl1)call).msg(msg);}
        else if(call.getClass() == North.class){((North)call).msg(msg);}
        else if(call.getClass() == Center.class){((Center)call).msg(msg);}
    }

    public void idPrg(int w){
        if(call.getClass() == Segl1.class){((Segl1)call).idPrg(w);}
        else if(call.getClass() == North.class){((North)call).idPrg(w);}
        else if(call.getClass() == Center.class){((Center)call).idPrg(w);}
    }

    public void dPrg(int w, int v){
        if(call.getClass() == Segl1.class){((Segl1)call).dPrg(w, v);}
        else if(call.getClass() == North.class){((North)call).dPrg(w, v);}
        else if(call.getClass() == Center.class){((Center)call).dPrg(w, v);}
    }

    private void addProj() throws Exception{
        SB refSeq = new SB();
        refSeq.loadFasta(Para.PATH_TO_TEMPLATE);
        Para.PID = Segl0.db.addProject(
            Para.P_TITLE,EPara.KMER_LEN,
            EPara.KMER_DENS,EPara.WORD_SKIP,
            EPara.MAT,EPara.GO,
            EPara.GE,EPara.MIS,
            EPara.MIS,EPara.MIN_R_LEN,
            EPara.MAX_R_LEN,EPara.MAXINDEL,
            refSeq.get(0).getTitle(),
            refSeq.get(0).getDNA()
        );
        ((Segl1)call).updateBrowsers();
    }

    private String getPBPath(int pid, int did){
        File dir = new File(".");
        String file = dir.getAbsolutePath()+File.separator+"assemblies"+File.separator+pid+"_"+did+".pass";
        File pb = new File(file);
        if(pb.exists()){return file;}
        return null;
    }

    private void rmProj() throws Exception{
        ArrayList <NK> data = Segl0.db.getDataNK(Para.P_ID_ADD_RM);
        for(int asp=0; asp<data.size(); asp++){
            File file = new File(getPBPath(Para.P_ID_ADD_RM, data.get(asp).getK()));
            if(file.exists()){file.delete();}
        }
        Segl0.db.rmDataByPID(Para.P_ID_ADD_RM);
        Segl0.db.rmProj(Para.P_ID_ADD_RM);
        ((Segl1)call).updateBrowsers();
    }

    private void addData(Segl1 L1_RpgsGui, String title, String path) throws Exception{
        int dKey = Segl0.db.addData(title, path, Para.P_ID_ADD_RM);
        createPBLOCK(Para.P_ID_ADD_RM, dKey);
        L1_RpgsGui.updateBrowsers();
        Para.POSTS = null;
        Para.POSTPROJID = -1;
    }

    public void rmData() throws Exception{
        File appsDir = new File(getPBPath(Para.P_ID_ADD_RM, Para.D_ID_ADD_RM));
        if(appsDir.exists()){appsDir.delete();}
        Segl0.db.rmDataByDID(Para.D_ID_ADD_RM);
        ((Segl1)call).updateBrowsers();
        Para.POSTS = null;
        Para.POSTPROJID = -1;
    }

    private void createPBLOCK(int pid, int did) throws Exception{
        SB iRefs = Segl0.db.getRef(pid);
        String path = Segl0.db.getPath(did);
        IB ib = new IB(iRefs.get(0));
        msg("Loading");
        idPrg(ProgBar.START);
        ib.load(path);
        idPrg(ProgBar.END);
        msg("Mapping");
        MB mb = match(ib, this);
        msg("Pairwise Aligning");
        PB pb = align(mb, this);
        if(Para.UPDATEREF){
            mb = null;
            msg("Consensus");
            ib.rpRef(Utils.charToString(Utils.rpGaps(Utils.getCon(getNucs(pb, this, -1), EPara.MIN_COV_CON), ib.getRef().getDNA())));
            msg("Re-mapping");
            mb = match(ib, this);
            ib = null;
            msg("Quality Distribution");
            mb.genQDist(this);
            msg("Pairwise Aligning");
            pb = align(mb, this);
            pb.setQDist(mb.getQDist());
            pb.setMaxQ(mb.getMaxQ());
            mb = null;
        }
        else{
            ib = null;
            msg("Quality Distribution");
            mb.genQDist(this);
            pb.setQDist(mb.getQDist());
            pb.setMaxQ(mb.getMaxQ());
            mb = null;
        }
        sortReads(pb);
        File dir = new File(".");
        pb.save(dir.getAbsolutePath()+File.separator+"assemblies"+File.separator+pid+"_"+did+".pass");
        msg("View Using Dropdown --->");
    }

    public void sortReads(PB pb){
        msg("Sorting");
        PR [] reads = new PR[pb.getSize()];
        int [] order = new int[pb.getSize()];
        for(int r=0; r<pb.getSize(); r++){
            reads[r] = pb.getRead(r);
            order[r] = pb.getRead(r).getStart();
        }
        this.dPrg(ProgBar.START, order.length);
        for(int z=0; z<order.length; z++){
            for(int x=z+1; x<order.length; x++){
                if(order[z] > order[x]){
                    int hold_o = order[z];
                    PR holder_r = reads[z];
                    order[z] = order[x];
                    reads[z] = reads[x];
                    order[x] = hold_o;
                    reads[x] = holder_r;
                }
            }
            this.dPrg(ProgBar.UPDATE, z);
        }
        this.dPrg(ProgBar.END, 0);
        ArrayList <PR> sorted = new ArrayList();
        for(int r=0; r<reads.length; r++){sorted.add(reads[r]);}
        pb.setReads(sorted);
    }

    private void resetDisplayData(){
        if(call.getClass() == North.class){
            ((North)call).resetCenterGUI();
            ((North)call).setNorthTabActiveState(North.HOME_TAB);
        }
        else if(call.getClass() == Segl1.class){
            ((Segl1)call).resetCenterGUI();
            ((Segl1)call).setNorthTabActiveState(North.HOME_TAB);
        }

        Para.PB = null;
        Para.NUCS = null;
        Para.HPS_CATS = null;
        Para.CON = null;
        Para.CODONS = null;
        Para.TREEDIDS = null;
        Para.TREE = null;
        Para.HEATMAP_DATA = null;
    }

    private void display() throws Exception{
        if(Para.D_ID!=-1){
            resetDisplayData();
            String path = getPBPath(Para.PID, Para.D_ID);
            if(path!=null){
                msg("Loading");
                idPrg(ProgBar.START);
                boolean PBLOCK_loaded = false;
                try{Para.PB = PB.load(path);PBLOCK_loaded = true;}
                catch(Exception e){PBLOCK_loaded = false;}
                idPrg(ProgBar.END);
                if(PBLOCK_loaded){
                    if(Para.PID == Para.POSTPROJID){
                        new Post(Para.PB, Para.POSTS).setPosts();
                        msg("Nucleotide Frequencies");
                        Para.NUCS = Processor.getNucs(Para.PB, this, (double)EPara.POSTFILT/100.00);
                        msg("Codon Frequencies");
                        Para.CODONS = getCodons(Para.PB, this, (double)EPara.POSTFILT/100.00);
                        countStopCodons();
                    }
                    else{
                        Para.POSTS = null;
                        Para.POSTPROJID = -1;
                        msg("Nucleotide Frequencies");
                        Para.NUCS = Processor.getNucs(Para.PB, this, -1);
                        msg("Codons");
                        Para.CODONS = getCodons(Para.PB, this, -1);
                        countStopCodons();
                    }
                    idPrg(ProgBar.START);
                    msg("HPS Locations");
                    Para.HPS_CATS = Utils.getHPSLens(Para.PB.getRef().getDNA());
                    msg("Consensus");
                    Para.CON = Utils.getCon(Para.NUCS, EPara.MIN_COV_CON);
                    idPrg(ProgBar.END);
                    Para.TREEDIDS = new int[1];
                    Para.TREEDIDS[0] = Para.D_ID;
                    heatMap();

                    if(call.getClass() == North.class){
                        ((North)call).updatePlots();
                        ((North)call).setNorthTabActiveState(North.TABLE_TAB);
                    }

                    msg("");
                    //((North)caller).setAllLabels(Para.FULL_ASSEMBLY.getNoOfReads()+"", fwd+"", rev+"", ((int)(len/Para.FULL_ASSEMBLY.getNoOfReads()))+"");
                }
                else{msg("Assembly Version not Compatible.");}
            }
            else{msg("Assembly file has been moved.");}
        }
    }

    private void rSave() throws Exception{
        PrintWriter outFile = new PrintWriter(new FileWriter(Utils.getFile(new JPanel(), false).getSelectedFile()), false);
        double thres = (double)EPara.POSTFILT/100.00;
        msg("Saving Reads");
        dPrg(ProgBar.START, Para.PB.getSize());
        for(int r=0; r<Para.PB.getSize(); r++){
            outFile.println(">"+r+"_startOnRef_"+Para.PB.getRead(r).getStart()+"_filterLvl_"+thres);
            outFile.println(Para.PB.getDNA(r, thres).replace("-", ""));
            dPrg(ProgBar.UPDATE, r);
        }
        dPrg(ProgBar.END, 0);
        msg(" ");
        outFile.close();
    }

    private void tSave() throws Exception{
        int [] T_HPS_CATS = Utils.getHPSLens(Para.PB.getRef().getDNA());
        char [] CON = Utils.getCon(Para.NUCS, EPara.MIN_COV_CON);
        double a_a, t_t, g_g, c_c, d_d, pA, pT, pG, pC;
        int cov;
        String path = "";
        if(batchSave.equals("")){path = Utils.getFile(new JPanel(), false).getSelectedFile().getPath();}
        else{path = batchSave+"_table.txt";}
        PrintWriter outFile = new PrintWriter(new FileWriter(path), false);
        if(Para.POSTS==null){outFile.println("Site\tCover\tAdenine\tThymine\tGuanine\tCytosine\tDeletion\tConsensus\thps\tCodons\t");}
        else{outFile.println("Site\tCover\tAdenine\tThymine\tGuanine\tCytosine\tDeletion\tP(A)\tP(T)\tP(G)\tP(C)\tConsensus\thps\tCodons\t");}
        msg("Saving Table");
        dPrg(ProgBar.START, CON.length);
        for (int s = 0; s < CON.length; s++){
            cov = Para.NUCS[0][s] + Para.NUCS[1][s] + Para.NUCS[2][s] + Para.NUCS[3][s] + Para.NUCS[4][s];
            a_a = (double)Para.NUCS[0][s]/(double)cov;t_t = (double)Para.NUCS[1][s]/(double)cov;
            g_g = (double)Para.NUCS[2][s]/(double)cov;c_c = (double)Para.NUCS[3][s]/(double)cov;
            d_d = (double)Para.NUCS[4][s]/(double)cov;
            if(Para.POSTS!=null){
                pA = Para.POSTS[0][s];
                pT = Para.POSTS[1][s];
                pG = Para.POSTS[2][s];
                pC = Para.POSTS[3][s];
            }
            else{pA=pT=pG=pC=0;}
            String codons = "";
            if((s - Para.FRAME)%3==0 && s<(Para.CON.length - 3)){
                HashMap <String, Integer> siteCodons = Para.CODONS[s];
                Iterator iter = siteCodons.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry pairs = (Map.Entry)iter.next();
                    String key = (String)pairs.getKey();
                    int value = ((Integer)pairs.getValue()).intValue();
                    codons = codons + key+":"+Utils.trans(key)+" ("+value+"), ";
                }
                codons = codons +" ["+ (codons.split(",").length - 1) +"]";
            }else{codons="";}
            boolean saveRow = false;
            double [] vals = {a_a, t_t, g_g, c_c};
            if(Utils.getSecondHighestValue(vals)>=((double)EPara.MIN_FREQ_HIGHLIGHT/100.00) && T_HPS_CATS[s]<=EPara.HPS_LENGTH){saveRow = true;}
            else{saveRow = false;}
            if(saveRow){
                outFile.println(s+"\t"+cov+"\t"+a_a+"\t"+t_t+"\t"+g_g+"\t"+c_c+"\t"+d_d+"\t"+pA+"\t"+pT+"\t"+pG+"\t"+pC+"\t"+CON[s]+"\t"+T_HPS_CATS[s]+"\t"+codons);
            }
            dPrg(ProgBar.UPDATE, s);
        }
        dPrg(ProgBar.END, 0);
        msg(" ");
        outFile.close();
    }

    public static HashMap <String, Integer> [] getCodons(PB block, Processor gp, double filter) throws Exception{return new Codon(block, gp, filter).getCodon();}
    public static int[][] getNucs(PB block, Processor gp, double filter) throws Exception {return new Nucs(block, gp).getNucs(filter);}
    public static IndelData getIndels(PB pbs, Processor gp) throws Exception {return new Indel(pbs, gp).getIndels();}
    private static MB match(IB initialData, Processor gp) throws Exception {return new Match(initialData, gp).getMB();}
    private static PB align(MB mb, Processor p) throws Exception {return (new Align(mb, p)).getAln();}

    private void genotype() throws Exception{
        IB ib = new IB(Para.PB.getRef());
        ib.add(new IR("Loc", Para.GENOQUERY, Para.GENOQUERY, 0));
        MB mb = match(ib, this);
        PB pb = align(mb, this);
        if(pb.getSize()<1){JOptionPane.showMessageDialog(null, "Could not Locate Region.", "alert", JOptionPane.ERROR_MESSAGE);}
        else{
            ArrayList <String> sList = new ArrayList();;
            if(Para.POSTS!=null){sList = Para.PB.getScDNA(pb.getStart(0), pb.getEnd(0), (double)EPara.POSTFILT/100.00);}
            else{sList = Para.PB.getScDNA(pb.getStart(0), pb.getEnd(0));}
            HashMap <String, Integer> hash = new HashMap <String, Integer>();
            String seq;
            for(int s=0; s<sList.size(); s++) {
                seq = sList.get(s);
                if(hash.containsKey(seq)){
                    int val = hash.get(seq).intValue();
                    hash.remove(seq);
                    hash.put(seq, ++val);
                }
                else{hash.put(seq, 1);}
            }
            Iterator iter = hash.entrySet().iterator();
            int c = 0;
            SB sb = new SB();
            while (iter.hasNext()) {
                Map.Entry pairs = (Map.Entry)iter.next();
                String dna = (String)pairs.getKey();
                int val = ((Integer)pairs.getValue()).intValue();
                sb.add(new Seq((c++), "SEQ_"+ (c++) +"_FREQ" + val, dna, false, val));
            }
            ArrayList <Integer> testCods = new ArrayList();
            for(int x=0; x<Para.GENOCODS.length; x++){if(Para.GENOCODS[x]){testCods.add(x);}}
            String tAA = "";
            for(int x=0; x<Para.GENOAA.length; x++){if(Para.GENOAA[x]){tAA += ","+Para.AAS[x];}}
            tAA = tAA.substring(1);
            String strDna = "";
            String [] cods;
            for(int s=0; s<sb.getSize(); s++){
                cods = new String[Para.GENOCODS.length];
                strDna = sb.get(s).getDNA();
                c = 0;
                String cod = "";
                for(int x=0; x<strDna.length(); x++){
                    cod += strDna.charAt(x);
                    if(cod.length()==3){
                        cods[c++] = cod;
                        cod = "";
                    }
                }
                boolean found = false;
                for(int x=0; x<testCods.size(); x++){if(tAA.indexOf(Utils.trans(cods[testCods.get(x)]))!=-1){found = true;}}
                sb.get(s).setTitle((sb.get(s).getTitle()+"_GENO"+found).toUpperCase());
            }
            String codsStr = "";
            for(int x=0; x<testCods.size(); x++){codsStr = codsStr + ","+testCods.get(x);}
            codsStr = codsStr.substring(1);
            String test = "If codons: "+codsStr.replaceAll(",", " (OR) ") + "\n";
            test = test + "contain: " + tAA.replaceAll(",", " (OR) ") + "\n";
            test = test + "then: TRUE \n";
            test = test + "else: FALSE \n";

            int tot = 0;
            int pass = 0;
            for(int s=0; s<sb.getSize(); s++){
                tot += sb.get(s).getVal();
                if(sb.get(s).getTitle().toUpperCase().indexOf("TRUE")!=-1){pass += sb.get(s).getVal();}
            }
            PrintWriter outFile = new PrintWriter(new FileWriter(Utils.getFile(new JPanel(), false).getSelectedFile()), false);
            outFile.println("Codon definition fragment: "+Para.GENOQUERY);
            outFile.println("Start on reference: " + pb.getStart(0));
            outFile.println("End on reference: " + pb.getEnd(0));
            outFile.println("");
            outFile.println(test);
            outFile.println("Total number of reads extracted: "+tot);
            outFile.println("Number passing the above test: "+pass);
            outFile.println("Number of variants: "+sb.getSize());
            outFile.println("");
            outFile.println("Individual variants and frequencies are:");
            outFile.println("");
            for(int s=0; s<sb.getSize(); s++){
                outFile.println(">"+sb.get(s).getTitle());
                outFile.println(sb.get(s).getDNA());
            }
            outFile.close();
        }
    }

    private void extTree() throws Exception{
        SB sb = new SB();
        sb.loadFasta(Para.EXTALNPATH);
        for(int s=0; s<sb.getSize(); s++){sb.get(s).setI(s);}
        if(sb!=null){
            if(sb.getSize()>5){
                Para.TREE = new NJ(this).build(sb, false);
                if(Para.TREE!=null){
                    Para.TREE.setStart(Para.TPOS);
                    Para.TREE.setEnd(Para.TPOS + Para.TREEWIN);
                    Para.TREE.setNodeColAndSize();
                    ((Center)call).loadCard(Segl2.TREE);
                    ((Center)call).updateTree();
                    msg("");
                }
                else{msg("Tree Could not be Build");}
            }
            else{
                ((Center)call).loadCard(Segl2.TREE);msg("Min. No. of Unique Sequences is 5");
            }
        }
        else{msg("Tree Could not be Build");}
    }

    private void tree() throws Exception{
        Para.TREE = null;
        ArrayList <String> paths = new ArrayList();
        for(int k=0; k<Para.TREEDIDS.length; k++){
            if(Para.TREEDIDS[k]!=-1){
                String path = getPBPath(Para.PID, Para.TREEDIDS[k]);
                if(path!=null){paths.add(path);}
            }
        }
        SB sb = new SB();
        msg("Loading Tree Data");
        dPrg(ProgBar.START, paths.size());
        for(int d=0; d<paths.size(); d++){
            PB pb = PB.load(paths.get(d));
            ArrayList <String> seqs = new ArrayList();;
            if(Para.POSTS!=null){
                new Post(pb, Para.POSTS).setPosts();
                seqs = pb.getScDNA(Para.TPOS, (Para.TPOS + Para.TREEWIN), (double)EPara.POSTFILT/100.00);
            }
            else{seqs = pb.getScDNA(Para.TPOS, (Para.TPOS + Para.TREEWIN));}
            HashMap <String, Integer> hash = new HashMap <String, Integer>();
            String seq;
            for(int s=0; s<seqs.size(); s++) {
                seq = seqs.get(s);
                if(hash.containsKey(seq)){
                    int val = hash.get(seq).intValue();
                    hash.remove(seq);
                    hash.put(seq, ++val);
                }
                else{hash.put(seq, 1);}
            }
            Iterator iter = hash.entrySet().iterator();
            int c = 0;
            while (iter.hasNext()) {
                Map.Entry pairs = (Map.Entry)iter.next();
                String dna = (String)pairs.getKey();
                int val = ((Integer)pairs.getValue()).intValue();
                String cod = "";
                for(int r=0; r<dna.length()-3; r++){
                    int t = Para.TPOS + r;
                    if((t - Para.FRAME)%3==0){
                        for(int y=0; y<Para.TCODS.length; y++){
                            if(t == Para.TCODS[y]){cod += "_" + Para.TCODS[y] + dna.substring(r, r+3);}
                        }
                    }
                }
                sb.add(new Seq((c++), "SEQ_"+ (c++) + cod+"_D" + d+"_FREQ" + val, dna, false, val) );
            }
            dPrg(ProgBar.UPDATE, d);
        }
        dPrg(ProgBar.END, 0);
        if(sb!=null){
            if(sb.getSize()>5){
                Para.TREE = new NJ(this).build(sb, false);
                if(Para.TREE!=null){
                    Para.TREE.setStart(Para.TPOS);
                    Para.TREE.setEnd(Para.TPOS + Para.TREEWIN);
                    Para.TREE.setNodeColAndSize();
                    ((Center)call).loadCard(Segl2.TREE);
                    ((Center)call).updateTree();
                    msg("");
                }
                else{msg("Tree Could not be Build");}
            }
            else{
                ((Center)call).loadCard(Segl2.TREE);msg("Min. No. of Unique Sequences is 5");
            }
        }
        else{msg("Tree Could not be Build");}
    }

    private void barcode() throws Exception{
        String path = "";
        LinkedList <String> bCodes = new LinkedList();
        LinkedList <String> sampleNames = new LinkedList();
        boolean bIn = false;
        if(!Para.BARCODES.equals("")){
            try{
                msg("Loading Barcodes");
                idPrg(ProgBar.START);
                FileReader file = new FileReader(Para.BARCODES);
                BufferedReader iFile = new BufferedReader(file);
                boolean again = true;String tln = "";
                do{
                    try{
                        tln = new String(iFile.readLine());
                        if(!tln.trim().equals("")){
                            String [] bits = tln.trim().split(" ");
                            if(bits.length>1){
                                bCodes.add(bits[0]);
                                sampleNames.add(bits[1]);
                            }
                            else{bCodes.add(tln);}
                        }
                    }
                    catch(Exception e){again = false;}
                }while(again);
                iFile.close();
                bIn = true;
                idPrg(ProgBar.END);
            }catch(Exception e){idPrg(ProgBar.END);bIn = false;msg("Could not Load Barcodes.");}
        }
        if(!Para.UNSORT.equals("") && bIn){
            //have a file writer for each of the barcodes
            PrintWriter [] of = new PrintWriter[bCodes.size()];
            String filename;

            String [] bits = Para.UNSORT.split(File.separator);
            String name = bits[bits.length-1];
            path = Para.UNSORT.substring(0, Para.UNSORT.lastIndexOf(name));

            for(int x=0; x<bCodes.size(); x++){
                if(sampleNames.size()>0){filename = path+""+sampleNames.get(x)+".fastq";}
                else{filename = path+""+bCodes+".fastq";}
                of[x] = new PrintWriter(new FileWriter(filename), false);
            }

            try{
                try {
                    BufferedReader iFile = new BufferedReader(new FileReader(Para.UNSORT));
                    boolean again = true;
                    int c = 1;
                    String title = "";String dna = "";String quals = "";
                    msg("Sorting Barcodes");
                    idPrg(ProgBar.START);
                    do {
                        try {
                            title = new String(iFile.readLine());
                            dna = new String(iFile.readLine().toUpperCase());
                            iFile.readLine();
                            quals = new String(iFile.readLine());
                            //for each barcode see where to put this read!!
                            for(int x=0; x<bCodes.size(); x++){
                                if(dna.length()>bCodes.get(x).length()){
                                    String code = bCodes.get(x);
                                    String frag = dna;
                                    boolean match = false;
                                    int ct = 0;
                                    for(int s=0; s<code.length(); s++){
                                        if(code.toUpperCase().charAt(s)!=frag.toUpperCase().charAt(s)){ct++;}
                                    }
                                    if(ct <= Para.TOLERATE){match=true;}
                                    else{match=false;}
                                    if(match && dna.length()==quals.length()){
                                        of[x].print(title+"\n");
                                        of[x].print(dna.substring(code.length()+Para.BUFF)+"\n");
                                        of[x].print("+"+"\n");
                                        of[x].print(quals.substring(code.length()+Para.BUFF)+"\n");
                                        x = bCodes.size() + 1;
                                    }
                                }
                            }
                        }catch (Exception e) {again = false;}
                    } while(again);
                    for(int x=0; x<bCodes.size(); x++){
                        of[x].flush();
                        of[x].close();
                    }
                    iFile.close();
                } catch (Exception e){}
                idPrg(ProgBar.END);
            }catch(Exception e){idPrg(ProgBar.END);msg("Could not Load Reads.");}
        }
    }

    private void vemeTable() throws Exception{
        int maxCov = -1;double maxNonCon = -1;
        SB ref = Segl0.db.getRef(Para.PID);
        int [] cov = new int[ref.get(0).getDNA().length()];
        char [] con =  new char[ref.get(0).getDNA().length()];
        char [] refSeq = Para.PB.getRef().getDNA().toCharArray();
        int [] nonCon = new int[Para.PB.getRef().getDNA().length()];

        dPrg(ProgBar.START, Para.NUCS[0].length);
        for(int s=0; s<Para.NUCS[0].length; s++){
            int [] nucFreqs = {Para.NUCS[0][s],Para.NUCS[1][s],Para.NUCS[2][s],Para.NUCS[3][s]};
            cov[s] = Utils.sum(nucFreqs);
            con[s] = refSeq[s];
            if(cov[s]==0){nonCon[s] = 0;}
            else{nonCon[s] = Utils.sumOmitMax(nucFreqs);}
            if(nonCon[s] > maxNonCon){maxNonCon = nonCon[s];}
            if(cov[s] > maxCov){maxCov = cov[s];}
            dPrg(ProgBar.UPDATE, s);
        }
        dPrg(ProgBar.END, 0);
        msg("INDELS");
        IndelData tINDELdata = getIndels(Para.PB, this);
        int[][] ins = tINDELdata.getIns();
        int[][] del = tINDELdata.getDels();

        int [] T_HPS_CATS = Utils.getHPSLens(Para.PB.getRef().getDNA());
        String path = "";
        if(batchSave.equals("")){path = Utils.getFile(new JPanel(), false).getSelectedFile().getPath();}
        else{path = batchSave+"_table.txt";}
        PrintWriter outFile = new PrintWriter(new FileWriter(path), false);
        outFile.println("site\tcover\ta\tt\tg\tc\tdel\tref\thps\tnon_con\tins_l_1\tins_l_2\tins_l_3\tins_l_4\tins_l_5\tdel_l_1\tdel_l_2\tdel_l_3\tdel_l_4\tdel_l_5\t");
        for(int s=0; s<Para.NUCS[0].length; s++){
            outFile.print(s + "\t" + cov[s] + "\t" + Para.NUCS[0][s] + "\t" + Para.NUCS[1][s] + "\t" + Para.NUCS[2][s] + "\t" + Para.NUCS[3][s] + "\t" + Para.NUCS[4][s] + "\t" + refSeq[s] + "\t" + T_HPS_CATS[s] + "\t" + nonCon[s] + "\t");
            for(int c=1; c<EPara.MAXINDEL; c++){outFile.print(ins[c][s] + "\t");}
            for(int c=1; c<EPara.MAXINDEL; c++){outFile.print(del[c][s] + "\t");}
            outFile.print("\n");
        }
        outFile.close();
    }

    String batchSave = "";
    private void process(String projTitle, String refPath, ArrayList <String> dataTitles, ArrayList <String> dataPaths){
        try{
            batchSave = "";
            SB refSeq = new SB();
            refSeq.loadFasta(refPath);
            int pid = Segl0.db.addProject(
                projTitle,
                EPara.KMER_LEN,EPara.KMER_DENS,EPara.WORD_SKIP,EPara.MAT,EPara.GO,
                EPara.GE,EPara.MIS,EPara.MIS,EPara.MIN_R_LEN,EPara.MAX_R_LEN,EPara.MAXINDEL,
                refSeq.get(0).getTitle(),
                refSeq.get(0).getDNA()
            );
            for(int d=0; d<dataTitles.size(); d++){
                System.out.println(projTitle + " : " + refPath + " : " + dataTitles.get(d) + " : " + dataPaths.get(d));
                int dKey = Segl0.db.addData(dataTitles.get(d), dataPaths.get(d), pid);
                Para.PID = pid; Para.D_ID = dKey;
                createPBLOCK(pid, dKey);
                display();
                batchSave =  projTitle+"_"+dataTitles.get(d);
                vemeTable();
                saveFastaScaffold(batchSave+"_reads.txt");
                System.out.println("    d: "+d);
            }
        }
        catch(Exception e){e.printStackTrace();}
    }

    private void addBatchs(){
        try {
            BufferedReader iFile = new BufferedReader(new FileReader(Utils.getFile(new JPanel(), true).getSelectedFile()));
            boolean again = true;
            String pTitle = "";String tPath = "";
            int c=0;
            do {
                try {
                    System.out.println("p:"+c++);
                    ArrayList <String> dTitles = new ArrayList();
                    ArrayList <String> dPaths = new ArrayList();
                    pTitle = new String(iFile.readLine());
                    int noOFDatasetsPerProject = new Integer(iFile.readLine()).intValue();
                    tPath = new String(iFile.readLine());
                    for(int d=0; d<noOFDatasetsPerProject; d++){
                        dTitles.add(iFile.readLine());
                        dPaths.add(iFile.readLine());
                    }
                    process(pTitle, tPath, dTitles, dPaths);
                    System.out.println("");
                } catch (Exception e) {again = false;}
            } while(again);
            iFile.close();
        } catch (Exception e){}
    }


    private void printAllTables() throws Exception{
        //for each project

        //for each dataset
    }

    public void saveFastaScaffold(String fname) throws Exception{
        PrintWriter outFile = new PrintWriter(new FileWriter(fname), false);
        for(int r=0; r<Para.PB.getSize();r++){
          StringBuffer gaps = new StringBuffer("");
          for(int x=0; x<Para.PB.getRead(r).getStart(); x++){gaps.append("-");}
          String line = gaps + "" + Para.PB.getScDNA(r);
          int noOFGapsRequiredAtEnd = (Para.PB.getRef().getDNA().length() - line.length()) + 1;
          gaps = new StringBuffer("");
          for(int x=0; x<noOFGapsRequiredAtEnd; x++){gaps.append("-");}
          line += gaps;
          outFile.println(">R"+r);
          outFile.println(line);
        }
        outFile.close();
    }
}